iT邦幫忙

DAY 15
2

emacs的30天學習筆記系列 第 37

懷舊C語言:1988 The C Programming Language 2nd Edition(PART VI)

  • 分享至 

  • xImage
  •  

在第一章 Introduction 引論裏,作者提到
C語言的很多重要設計來自於BCPL語言(大師也是遵從不要重新打造輪子的道理),
Martin Richards所開發的。而BCPL受到由Ken
Thompson in 1970 在DEC PDP-7主機上的第一台UNIX開發的B語言所影響,
這時,不禁納悶,眾所皆知UNIX不是由C語言開發的嗎? 記憶模糊了。在電腦科學的早期,
常常程式語言的發明者也往往是作業系統的發明者,語言和系統,語言和硬體是緊密連接的,
而40,50年過去,分工愈來愈細(小公司MIS什麼都幹,大公司MIS就分可以分工)。軟體工程漸趨
完備,有些人做底層,有些人做介面(GUI),有些人做商業邏輯,有些人做品保測試。
台灣之光HTC無疑是人機介面的強者,近幾年也投了不少錢發展內容(雲端)。
只是獨大市場卻是三星,希望大家多支持國貨,寧願你買Apple, 也不要買三星。扯遠了。

圖靈獎得主Knuth曾說,4/50年前,一個電腦科學家就能了解電腦科學8,9成,但是現在了解個2,3成就很不容易了。Knuth 本身也體現了,語言發明者,作業系統發明者於一身,當然不朽於後世是他那一套寫了二/三十年還沒寫完的鉅著。

可是筆者想要提的是DEC PDP-7,DEC 是迪吉多,當他被康柏併購時,小時候的印象以為他是做PC的,可是一查WIKI,才知道迪吉多是此馬來頭大,和昇揚公司,都是軟硬通吃的公司,指的是CPU設計開發生產。PDP系列,在早期UNIX/LINUX的開展史,顯然佔有不可磨滅的地位,所以linux支援x86之外,會支援ALPHA CPU結構,就是迪吉多的緣故 。
它的作業系統基本上,這些前輩都不用,都在它的機器上開發別的作業系統,或是寫下不朽的AP(EAMACS),留名的都是這些附屬品,本尊只有機器的型號留下,但也反應了PDP系列在校園裏多風行。在那個年代,做主機的廠商不少家,至少IBM一定是,可能迪吉多很賺,才會找了那麼多電腦奇才來公司上班。

當然他的員工,Dave Cutler ,1988年離開,前往微軟開發WIN NT, wiki上寫著
試圖打造an "open" operating system (覺得wiki的作者也不是很客觀),跑在比x86還強的架構上。
open,筆者發現,連HTC, APPLE, 都喜歡用OPEN, 覺得真有open mind,close source 這種道理嗎?

SUN 也被oracle併了,電腦界的元老師碩果僅存的大概只剩xerox/IBM, 還在商業市場中生存,只是全錄幾乎很明顯的在商業產品上以OA為主力,才不致於被IT大公司併購,而IBM是大象會跳舞,不像SUN軟硬都吃,轉型以高價服務為主。也許有這些前車之鑑,IT大公司不再通吃軟硬。

WIKI 上,把迪吉多蓋棺論定,幾乎在商用電腦,database,乙太網路,終端模擬,X Window都留下歷史定位,這麼牛的公司,藉著WIKI,讓筆者認識它。感謝WIKI.

言歸正傳,瑞查先生發明的C語言,當然有和前人的輪子不同的改良,
他說:BCPL and B are ``typeless''無型別語言,相反地,C提供了各種各樣多樣的型別。
讓人眼冒金的指標也是一種型別,一顆星***,兩顆星****,就是不同的型別,,而且是強型別的語言。

邦友分享了node.js的使用,最近火紅的老語言,大概就是javascript,藉著google 的javascript vm(V8 )直接縱橫於server端,且效能不俗,就javascript不像java是有型別的語言,javascript實在和java關係不大,javascript明顯的是script語言中,無型別的代表,
只要var ,就是變數,感覺,在閱讀上,就是很不習慣,型別基本上也會帶來可讀性,不用型別,
沒法從型別上來望文生義。而且一個基本的有/無型別分水嶺,就會造成不同的寫作風格,
所以看邦友node.js的文章, 常常也是英文字看得懂,意思不太懂。常常有人認為無型別的語言比較好學,覺得好像也沒有。真得體貼到程式員嗎?就筆者而言,總是沒有用到一個語言的精華,都只有tutorial的水平。

接著昨天快速排序的中級版。

#include <stdio.h>
#include <string.h>
#define MAXLINES 5000 /* max #lines to be sorted */
char *lineptr[MAXLINES]; /* pointers to text lines */
int readlines(char **lineptr, int nlines);
void writelines(char **lineptr, int nlines);
void qsort(char **lineptr, int left, int right);
int getline(char *, int);

//int getline(char *s,int lim);  //s[]->*s
/* sort input lines */
main()
{
int nlines; /* number of input lines read */
if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
qsort(lineptr, 0, nlines-1);
writelines(lineptr, nlines);
return 0;
} else {
printf("error: input too big to sort\n");
return 1;
}
}

#define MAXLEN 1000 /* max length of any input line */
char *alloc(int);
/* readlines: read input lines */
int readlines(char **lineptr, int maxlines)
{
int len, nlines;
char *p, line[MAXLEN];
nlines = 0;
while ((len = getline(line, MAXLEN)) > 0)
if (nlines >= maxlines || (p = alloc(len)) == NULL)
return -1;
else {
line[len-1] = '\0'; /* delete newline */
strcpy(p, line);
//lineptr[nlines++] = p;
  *(lineptr+nlines++)= p;
}
return nlines;
}
/* writelines: write output lines */
void writelines(char **lineptr, int nlines)
{
int i;
for (i = 0; i < nlines; i++)
printf("%s\n", *(lineptr+i));
}

//char *lineptr[MAXLINES]
/* writelines: write output lines 
void writelines(char *lineptr[], int nlines)
{
while (nlines-- > 0)
printf("%s\n", *lineptr++);
}
*/

/* qsort: sort v[left]...v[right] into increasing order */
void qsort(char **v, int left, int right)
{
int i, last;
void swap(char **v, int i, int j);
if (left >= right) /* do nothing if array contains */
return; /* fewer than two elements */
swap(v, left, (left + right)/2);
last = left;
for (i = left+1; i <= right; i++)
if (strcmp(*(v+i), *(v+left)) < 0)
swap(v, ++last, i);
swap(v, left, last);
qsort(v, left, last-1);
qsort(v, last+1, right);
}

/* swap: interchange v[i] and v[j] */
void swap(char **v, int i, int j)
{
char *temp;
temp = *(v+i);
*(v+i) = *(v+j);
*(v+j) = temp;
}

#define ALLOCSIZE 10000 /* size of available space */
static char allocbuf[ALLOCSIZE]; /* storage for alloc */
static char *allocp = allocbuf; /* next free position */
char *alloc(int n) /* return pointer to n characters */
{
	if (allocbuf + ALLOCSIZE - allocp >= n) { /* it fits */
	allocp += n;
	return allocp - n; /* old p */
	} else /* not enough room */
	return 0;
}
void afree(char *p) /* free storage pointed to by p */
{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
allocp = p;
}

int getline(char *s,int lim)  //s[]->*s
{
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
*(s+i) = c; //s[i]

if (c == '\n') {
*(s+i) = c; // s[i]
++i;
}
*(s+i) = '\0'; //s[i]
return i;
}

程式的測試結果:

$ a
You
Give
Love
A
Bad
Name
^Z
A
Bad
Give
Love
Name
You

字串的排序。^Z之前是待排序的字串,^Z之後是排好序。
因為C的字串是 char*, 所以字串陣列是 char* str[]由之前的討論,
str[] 又可表成 *str , 所以整個 表示成 char **str。上面的code,是從書中的code,
改成2個
*的版本。
原版在最後面。
相比之下,基本上只有宣告的部分,修改,在程式裏面的運算,仍然是只有1個
*

這程式用到static char allocbuf[ALLOCSIZE]; /* storage for alloc */
這個來做中介的諸存,
它是一段,一段,一段,一段來儲存,

和傳統的把把陣列的長度決定好,等長字串構成的陣列,不一樣。
p = alloc(len) 先取得一個長度的位置,
strcpy(p, line); 把值放入allocbuf[ALLOCSIZE];
*(lineptr+nlines++)= p;再給另一個字串陣列。
比傳統的寫法多一步,多了分配p = alloc(len),空間用起來節省多了。

(gdb) p &allocbuf
$1 = (char (*)[10000]) 0x406020
(gdb) p allocp
$2 = 0x406026 ""
(gdb) n
91 allocp += n;
(gdb) n
92 return allocp - n; /* old p */
(gdb) p allocp
$3 = 0x406034 ""
(gdb) n

(gdb) p allocp
$4 = 0x40603e ""

0x406020 ,0x406026,0x406034,0x40603e
在原書上,在5.4 Address Arithmetic,算是很節省的用空間。
因為不常用這種寫法,特別寫出來。

^ZCtrl Z也是EOF.

程式才會停止輸入,排序。
qsort函數裏有一行宣告。昨天沒發現,

void swap(char **v, int i, int j);

實驗一下,發現C語言,如果你要叫用的函數,如swap,你要放在上面(前面),順序是
call的程式, call的程式。但是通常不這樣寫,會寫成 被call的程式原型,call的程式,call的程式,以本例而言,因為是copy來的,
發現只要相對位置正確,並沒有一定要把程式原型集中放在上方。
#DEFINE也可以放。

#include <stdio.h>
#include <string.h>
#define MAXLINES 5000 /* max #lines to be sorted */
char *lineptr[MAXLINES]; /* pointers to text lines */
int readlines(char *lineptr[], int nlines);
void writelines(char *lineptr[], int nlines);
void qsort(char *lineptr[], int left, int right);
int getline(char *s,int lim);  //s[]->*s
/* sort input lines */
main()
{
int nlines; /* number of input lines read */
if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
qsort(lineptr, 0, nlines-1);
writelines(lineptr, nlines);
return 0;
} else {
printf("error: input too big to sort\n");
return 1;
}
}

#define MAXLEN 1000 /* max length of any input line */
int getline(char *, int);
char *alloc(int);
/* readlines: read input lines */
int readlines(char *lineptr[], int maxlines)
{
int len, nlines;
char *p, line[MAXLEN];
nlines = 0;
while ((len = getline(line, MAXLEN)) > 0)
if (nlines >= maxlines || (p = alloc(len)) == NULL)
return -1;
else {
line[len-1] = '\0'; /* delete newline */
strcpy(p, line);
lineptr[nlines++] = p;
}
return nlines;
}
/* writelines: write output lines */
void writelines(char *lineptr[], int nlines)
{
int i;
for (i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
}

//char *lineptr[MAXLINES]
/* writelines: write output lines 
void writelines(char *lineptr[], int nlines)
{
while (nlines-- > 0)
printf("%s\n", *lineptr++);
}
*/
/* swap: interchange v[i] and v[j] */
void swap(char *v[], int i, int j)
{
char *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}


//void swap(char *v[], int i, int j);
/* qsort: sort v[left]...v[right] into increasing order */
void qsort(char *v[], int left, int right)
{
int i, last;
//void swap(char *v[], int i, int j);
if (left >= right) /* do nothing if array contains */
return; /* fewer than two elements */
swap(v, left, (left + right)/2);
last = left;
for (i = left+1; i <= right; i++)
if (strcmp(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last);
qsort(v, left, last-1);
qsort(v, last+1, right);
}


#define ALLOCSIZE 10000 /* size of available space */
static char allocbuf[ALLOCSIZE]; /* storage for alloc */
static char *allocp = allocbuf; /* next free position */
char *alloc(int n) /* return pointer to n characters */
{
if (allocbuf + ALLOCSIZE - allocp >= n) { /* it fits */
allocp += n;
return allocp - n; /* old p */
} else /* not enough room */
return 0;
}
void afree(char *p) /* free storage pointed to by p */
{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
allocp = p;
}

int getline(char *s,int lim)  //s[]->*s
{
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
*(s+i) = c; //s[i]

if (c == '\n') {
*(s+i) = c; // s[i]
++i;
}
*(s+i) = '\0'; //s[i]
return i;
}

上一篇
懷舊C語言:1988 The C Programming Language 2nd Edition(PART V)
下一篇
懷舊C語言:1988 The C Programming Language 2nd Edition(PART VII)
系列文
emacs的30天學習筆記38
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
chiounan
iT邦研究生 1 級 ‧ 2011-11-16 09:17:23

建議您程式碼可以作適當的排版。
謝謝

我要留言

立即登入留言